#include "ShipManageB.h"
#include <QDebug>
// #include "SerialManage.h"
//  #include "networkmanage.h"
#include "MsgParser.h"
#include "dbdata.h"
#include "gtime.h"
#include "ShipMutex.h"
#include "commonutil.h"
#include "geographicutil.h"
#include <QRandomGenerator>
#include "shipAlgorithm/ShipCollision.h"
#include "LonLatUtil.h"
#include "poicheck.h"
#include <QSettings>
#include <QCoreApplication>
#include "mylogger.h"

using namespace ns_yht;

namespace
{
#define MAX_COLLISION_COUNT 100      // 会遇船舶数量上限
#define LONLATDISTANCE_THRESHOLD 0.1 // 与本船经纬度相差该值则忽略该船
}

ShipManageB::ShipManageB()
{

    m_ownShip.reset(new ModelShip);

    connect(MSGPARSER, &MsgParser::ais1Finished, this, &ShipManageB::onAis1Finished);
    connect(MSGPARSER, &MsgParser::ais4Finished, this, &ShipManageB::onAis4Finished);
    connect(MSGPARSER, &MsgParser::ais5Finished, this, &ShipManageB::onAis5Finished);
    connect(MSGPARSER, &MsgParser::ais18Finished, this, &ShipManageB::onAis18Finished);
    connect(MSGPARSER, &MsgParser::ais24Finished, this, &ShipManageB::onAis24Finished);

    connect(MSGPARSER, &MsgParser::HDTFinished, this, &ShipManageB::onHDTFinished);
    connect(MSGPARSER, &MsgParser::HDGFinished, this, &ShipManageB::onHDGFinished);
    connect(MSGPARSER, &MsgParser::GGAFinished, this, &ShipManageB::onGGAFinished);
    connect(MSGPARSER, &MsgParser::GLLFinished, this, &ShipManageB::onGLLFinished);
    connect(MSGPARSER, &MsgParser::RMCFinished, this, &ShipManageB::onRMCFinished);
    connect(MSGPARSER, &MsgParser::VTGFinished, this, &ShipManageB::onVTGFinished);
    connect(MSGPARSER, &MsgParser::GNSFinished, this, &ShipManageB::onGNSFinished);

    connect(MSGPARSER, &MsgParser::DPTFinished, this, &ShipManageB::onDPTFinished);
    connect(MSGPARSER, &MsgParser::posStateChange, this, &ShipManageB::onposStateChange);

    connect(MSGPARSER, &MsgParser::zdaFinished, this, [=](ZDA *zda)
            { GTime::setUtcTime(zda->ctime, zda->zoneDiff); delete zda; });

    QSettings setting(QCoreApplication::applicationDirPath() + "/setting.ini", QSettings::IniFormat);
    m_filterMode = setting.value("FilterMode", 0).toInt();
    m_dcpaLimit = setting.value("DCPA", 1).toDouble() * 1852;
    m_tcpaLimit = setting.value("TCPA", 10).toDouble();
    m_front = setting.value("Front", 1852).toDouble();
    m_back = 0; // setting.value("Back", 100).toDouble();
    m_left = setting.value("Left", 100).toDouble();
    m_right = setting.value("Right", 100).toDouble();
    m_ownShip.reset(new ModelShip);
    m_ownShip->mmsi = setting.value("MMSI", 0).toULongLong();
    m_elapsedTimer.start();
}

ShipManageB::~ShipManageB()
{
}

void ShipManageB::newInstance()
{
    if (!g_shipManage)
        new ShipManageB;
}

void ShipManageB::startThread(QThread &thread)
{

    ShipManage::startThread(thread);

    updateShips();
}

void ShipManageB::searchOneShip(quint64 mmsi, int panelId)
{
    m_panelId = panelId;
    QSharedPointer<ModelShip> model;
    bool isNewShip;
    if (!m_ownShip.isNull() && mmsi == m_ownShip->mmsi)
        model = m_ownShip;
    else
        model = getOrNewShip(mmsi, false, isNewShip);
    m_searchedShip = model;
    emit searchOneShipFinished();
}

void ShipManageB::searchShipWithKeyword(const QString &keyword, int panelId)
{
    m_panelId = panelId;
    DBDATA->getShipList(keyword, m_searchedResult);
    emit searchShipsWithKeywordFinished();
}
void ShipManageB::searchTrack(quint64 mmsi, const QString &startTime, const QString &endTime)
{
}
void ShipManageB::request()
{
}

QSharedPointer<ModelShip> ShipManageB::getOrNewShip(quint64 mmsi, bool vdo, bool &isNewShip)
{
    QSharedPointer<ModelShip> ship;
    if (vdo)
    {
        ship = m_ownShip;
        ship->mmsi = mmsi;
        isNewShip = false;
    }
    else
    {
        if (mmsi == m_ownShip->mmsi)
        {
            ship = m_ownShip;
            isNewShip = false;
        }
        else if (m_shipList.contains(mmsi))
        {
            ship = m_shipList[mmsi];
            isNewShip = false;
        }
        else
        {
            ship.reset(new ModelShip);
            ship->mmsi = mmsi;
            m_shipList[mmsi] = ship;
            // 从本地船舶数据库查询该船舶的静态信息
            //            QString enName, cnName, nationality;
            //            int typeId{0};
            //            if (DBDATA->getShipInfo(mmsi, enName, cnName, nationality, typeId))
            //            {
            //                ship->enname = enName;
            //                ship->cnname = cnName;
            //                ship->nation = nationality;
            //                ship->type = typeId;
            //            }

            isNewShip = true;
        }
    }
    return ship;
}

void ShipManageB::updateShips()
{
    static int updateTimes = 0;
    if (/*m_shipList.count() >= 20 && */ m_elapsedTimer.elapsed() < 3000 || m_isBusy)
        return;
    if (updateTimes >= 60) // 处理过期船舶
    {
        processExpiredShips();
        updateTimes = 0;
    }
    MyLogger::developInfo(QString("ship count: %1").arg(m_shipList.count()).toStdString());
    updateTimes++;
    m_elapsedTimer.restart();

    if (!m_ownShip.isNull() && LonLatUtil::isValid(m_ownShip->lat, m_ownShip->lon))
    {
        m_aisCount = 0;
        m_arpaCount = 0;
        int dangerousCount = 0;
        foreach (auto s, m_shipList)
        {
            updateShip(s);
            if (s->dangerous)
                dangerousCount++;
        }
        if (dangerousCount == 0)
            emit cancelAllShipCollision();
#if 0
        // for (auto it = m_shipList.begin(); it != m_shipList.end();)//这个迭代会指向野指针，需要查找原因
        foreach (auto s, m_shipList)
        {
            // auto key = it.key();
            // auto s = it.value();

            if (LonLatUtil::isValid(s->lat, s->lon))
                s->distance = GeographicUtil::getGeoDistance(QYHHMap::Coordinate(m_ownShip->lat, m_ownShip->lon), QYHHMap::Coordinate(s->lat, s->lon), true);
            else
                s->distance = -1;

            if (s->distance > m_radius || s->distance < 0)
            {
                s->inRadius = false;
                // 如果刚刚搜索了这条船舶，先去掉选中（搜索）
                if (!m_searchedShip.isNull() && m_searchedShip->mmsi == s->mmsi)
                {
                    m_searchedShip.clear();
                    emit searchOneShipFinished();
                }
                // 如果该船舶在危险船舶列表中，也要先去掉
                //  先该船舶原先在m_dangerousShipList中的位置，-1表示原来没有
                int n = m_dangerousShipList.count();
                for (int i = 0; i < n; i++)
                {
                    if (m_dangerousShipList.at(i)->mmsi == s->mmsi)
                    {
                        m_dangerousShipList.at(i)->dangerous = false;
                        m_dangerousShipList.removeAt(i);
                        emit cancelShipCollision(s->mmsi);
                        break;
                    }
                }

                // it = m_shipList.erase(it); //从列表中删除; 或者不删除，显示时做控制;这行和下面行二选一
                // it++;
            }
            else
            {
                // it++;
                s->inRadius = true;
                if (s->msgtype == EMsgType::ARPA)
                    m_arpaCount++;
                else
                    m_aisCount++;
            }
        }
        // 计算方位，更新会遇列表
        foreach (auto s, m_shipList)
        {
            if (!s->inRadius)
                continue;
            s->direction = GeographicUtil::getGeoAngle(QYHHMap::Coordinate(m_ownShip->lat, m_ownShip->lon), QYHHMap::Coordinate(s->lat, s->lon));
            if (s->direction < 0)
                s->direction += 360;
            s->dangerous = false;
            if (s->distance < ALLSETTINGS.alertSetting.limitValue.dcpa)
            {
                s->dangerous = true;
                s->tcpa = 0;
            }
            else
            {
                // bool dangerous = ShipCollision::CollisionCheck(m_ownShip->sog, m_ownShip->cog, m_ownShip->lon, m_ownShip->lat, m_ownShip->time, s->sog, s->cog, s->lon, s->lat, s->time, s->dcpa, s->tcpa);
                // s->dcpa *= GeographicUtil::MetersPerNM;
                // qInfo() << "CollisionCheck==========================" << s->mmsi << s->dcpa << s->tcpa << ALLSETTINGS.alertSetting.limitValue.dcpa;
                // if (dangerous)
                // dangerous = (s->dcpa <= ALLSETTINGS.alertSetting.limitValue.dcpa && s->tcpa <= ALLSETTINGS.alertSetting.limitValue.tcpa);

                s->dangerous = ShipCollision::meetCheck(m_ownShip->sog, m_ownShip->cog, m_ownShip->lon, m_ownShip->lat, m_ownShip->time, s->sog, s->cog, s->lon, s->lat, s->time, ALLSETTINGS.alertSetting.limitValue.dcpa, s->tcpa);
                if (s->dangerous)
                    s->dangerous = (s->tcpa <= ALLSETTINGS.alertSetting.limitValue.tcpa);
            }

            int n = m_dangerousShipList.count();
            // 先该船舶原先在m_dangerousShipList中的位置，-1表示原来没有；在的话先从列表中拿出来
            int pindex = -1;
            for (int i = 0; i < n; i++)
            {
                if (m_dangerousShipList.at(i)->mmsi == s->mmsi)
                {
                    pindex = i;
                    m_dangerousShipList.remove(i);
                    n--;
                    break;
                }
            }

            if (s->dangerous)
            {
                // 判断该船舶现在应该放在什么位置
                int index = n;
                for (int i = 0; i < n; i++)
                {
                    if (s->tcpa < m_dangerousShipList.at(i)->tcpa)
                    {
                        index = i;
                        break;
                    }
                }
                // 最多只显示5条危险船舶
                // if (pindex >= 0 && pindex != index && pindex != index - 1)
                // { // 原来在列表中，变更顺序
                //     if (index > pindex)
                //         m_dangerousShipList.move(pindex, index - 1);
                //     else
                //         m_dangerousShipList.move(pindex, index);
                //     emit shipCollisionAlarm(s.data()); // 需要刷新DCPA和TCPA
                // }
                // else if (pindex < 0 && index < 5)
                if (index < 5)
                { // 原来没在列表中，新增
                    if (index < n)
                    {
                        m_dangerousShipList.insert(index, s);
                        s->dangerousEnsured = false;
                    }
                    else
                        m_dangerousShipList.append(s);
                    n++;
                    if (n > 5)
                    {
                        auto ls = m_dangerousShipList.takeLast();
                        ls->dangerous = false;
                        emit cancelShipCollision(ls->mmsi);
                    }

                    emit shipCollisionAlarm(s.data());
                }
            }
            else if (pindex >= 0) // 上次判断是危险船舶，现在变成非危险船舶
            {
                s->dangerous = false;
                // m_dangerousShipList.removeAt(pindex); //这里不需要删除，因为获取pindex时已经删除了
                emit cancelShipCollision(s->mmsi);
            }
    }
#endif
    }

    emit shipsChanged();
    POICHECK->check();
}

void ShipManageB::updateShip(QSharedPointer<ModelShip> s, bool refreshDistance, bool isAdd)
{
    if (!LonLatUtil::isValid(s->lat, s->lon))
        return;

    // auto cancelCollision = [=](quint64 mmsi)
    // {
    //     if (m_shipCollisionMap.contains(mmsi))
    //     {
    //         if (GLOG)
    //             GLOG->debug("cancel ship collision-----------------{}", mmsi);
    //         m_shipCollisionMap.remove(mmsi);
    //         emit cancelShipCollision(mmsi);
    //     }
    // };

    s->dangerous = false;
    int stype = s->getShipType();

    if (stype == EShipType::NavigationMark || stype == EShipType::NetMark)
    {
        cancelCollision(s->mmsi);
        return;
    }
    if (m_filterMode == 1)
    {
        if (stype == EShipType::Fish || (s->length() > 0 && s->length() < 36))
        {
            cancelCollision(s->mmsi);
            return;
        }
    }
    else if (m_filterMode == 2)
    {
        if (stype != EShipType::Fish /*|| s->length() >= 36*/)
        {
            cancelCollision(s->mmsi);
            return;
        }
    }

#if 1 // yu 2025-05-16
    // 本船在航行中才进行危险判断
    if (m_ownShip->getStatusOfSog() == ShipStatusOfSog::Voyaging && s->sog > 3 && qAbs(m_ownShip->lat - s->lat) < LONLATDISTANCE_THRESHOLD && qAbs(m_ownShip->lon - s->lon) < LONLATDISTANCE_THRESHOLD)
    {
        s->dangerous = ShipCollision::CollisionCheck(m_ownShip->sog, m_ownShip->cog, m_ownShip->lon, m_ownShip->lat, m_ownShip->time, s->sog, s->cog, s->lon, s->lat, s->time, s->dcpa, s->tcpa);
        if (s->dcpa > 0)
            s->dcpa *= GeographicUtil::MetersPerNM;
        if (s->dangerous)
            s->dangerous = (s->tcpa <= m_tcpaLimit && s->dcpa <= m_dcpaLimit);
    }
    else
        s->dangerous = false;

    // if (MyLogger::developDebug && s->mmsi == 563171800)
    // {
    //     GLOG->debug("mmsi:{} stype:{} dcpa:{}  tcpa:{}  sog:{}", s->mmsi, stype, s->dcpa, s->tcpa, s->sog);
    // }

    bool preDangerous = m_shipCollisionMap.contains(s->mmsi);
    if (s->dangerous)
    {
        if (preDangerous)
        {
        }
        else
        {
            if (GLOG)
                GLOG->debug("ship collision-----------------{},{},{},{},{}", s->mmsi, s->dcpa, s->tcpa, s->type, stype);
            m_shipCollisionMap.insert(s->mmsi, SimpleShipInfo{s->dcpa, s->tcpa, s->getName(), true, GTime::getUtcTime_s()});
            emit autoShipCollision(s->mmsi, false);
        }
    }
    else if (preDangerous)
    {
        if (GLOG)
            GLOG->debug("cancel ship collision-----------------{}", s->mmsi);
        m_shipCollisionMap.remove(s->mmsi);
        emit cancelShipCollision(s->mmsi);
    }
#endif

#if 0 // zhuledan
    if (s->distance < m_dcpaLimit)
    {
        s->dangerous = true;
        s->tcpa = 0;
    }
    else
    {
        s->dangerous = ShipCollision::meetCheck(m_ownShip->sog, m_ownShip->cog, m_ownShip->lon, m_ownShip->lat, m_ownShip->time, s->sog, s->cog, s->lon, s->lat, s->time, 0.5 * 1852.0, s->dcpa, s->tcpa);
        if (s->dangerous)
            s->dangerous = (s->tcpa <= m_tcpaLimit);
    }
    bool preDangerous = m_shipCollisionMap.contains(s->mmsi);

    if (s->dangerous)
    {
        if (preDangerous)
        {
            qInfo() << "ship collision" << s->mmsi << s->dcpa << s->tcpa;
            if (s->dcpa >= 370 && s->dcpa <= 926)
            {
                if (!m_shipCollisionMap[s->mmsi].ensured)
                {
                    qint64 tm = GTime::getUtcTime_s() - m_shipCollisionMap[s->mmsi].time;
                    qInfo() << "ship collision ensured" << s->mmsi << tm;
                    if (tm > 180)
                    {
                        m_shipCollisionMap[s->mmsi].ensured = true;
                        emit autoShipCollision(s->mmsi, true);
                    }
                }
            }
            else
            {
                if (m_shipCollisionMap[s->mmsi].ensured)
                {
                    m_shipCollisionMap[s->mmsi].ensured = false;
                    m_shipCollisionMap[s->mmsi].time = GTime::getUtcTime_s();
                    emit autoShipCollision(s->mmsi, false);
                }
            }
        }
        else
        {
            m_shipCollisionMap.insert(s->mmsi, SimpleShipInfo{s->dcpa, s->tcpa, s->getName(), true, GTime::getUtcTime_s()});
            emit shipCollisionAlarm(s->mmsi, s->tcpa, s->getName());
        }
    }
    else if (preDangerous)
    {
        m_shipCollisionMap.remove(s->mmsi);
        emit cancelShipCollision(s->mmsi);
    }
#endif

#if 0
    int n = m_dangerousShipList.count();
    // 先该船舶原先在m_dangerousShipList中的位置，-1表示原来没有；在的话先从列表中拿出来
    int pindex = -1;
    for (int i = 0; i < n; i++)
    {
        if (m_dangerousShipList.at(i)->mmsi == s->mmsi)
        {
            pindex = i;
            m_dangerousShipList.remove(i);
            n--;
            break;
        }
    }

    if (s->dangerous)
    {
        // 判断该船舶现在应该放在什么位置
        int index = n;
        for (int i = 0; i < n; i++)
        {
            if (s->tcpa < m_dangerousShipList.at(i)->tcpa)
            {
                index = i;
                break;
            }
        }
        // 最多只显示5条危险船舶
        if (index < 5)
        {
            m_dangerousShipList.insert(index, s);
            if (pindex < 0) // 说明这是新增的危险船舶
                s->dangerousEnsured = false;
            n++;
            if (n > 5) // 超出5条，去掉最后一条
            {
                auto ls = m_dangerousShipList.takeLast();
                ls->dangerous = false;
                emit cancelShipCollision(ls->mmsi);
            }

            emit shipCollisionAlarm(s->mmsi, s->tcpa, s->getName());
        }
        else // 排序在5条之外
        {
            s->dangerous = false;
            if (pindex >= 0) // 上次判断是危险船舶，现在超出5条，作为非危险船舶 // 这里不需要删除，因为获取pindex时已经删除了
                emit cancelShipCollision(s->mmsi);
        }
    }
    else if (pindex >= 0) // 上次判断是危险船舶，现在变成非危险船舶 // 这里不需要删除，因为获取pindex时已经删除了
    {
        emit cancelShipCollision(s->mmsi);
    }
#endif
}

void ShipManageB::cancelCollision(quint64 mmsi)
{
    if (m_shipCollisionMap.contains(mmsi))
    {
        if (GLOG)
            GLOG->debug("cancel ship collision-----------------{}", mmsi);
        m_shipCollisionMap.remove(mmsi);
        emit cancelShipCollision(mmsi);
    }
}

void ShipManageB::updateAlertArea()
{
    if (!ownValid())
        return;
    m_alertAreas.clear();
#if 0 // zhuledan
    double radius = 1852.0;
    Coordinates alertArea;
    GeographicUtil::getPointCircle(m_ownShip->lat, m_ownShip->lon, radius, alertArea, 64);
    m_alertAreas.append(alertArea);
#endif

#if 1 // yu 2025-05-16
    Coordinates coors;
    double angle = m_ownShip->cog; // m_ownShip->getAngle();
    double lat2, lon2, lat3, lon3;
    Coordinates alertArea;
    GeographicUtil::getCoordinate(m_ownShip->lat, m_ownShip->lon, angle + 180, m_back, lat2, lon2);
    GeographicUtil::getCoordinate(lat2, lon2, angle - 90, m_left, lat2, lon2);
    alertArea.append(Coordinate(lat2, lon2));
    GeographicUtil::getCoordinate(lat2, lon2, angle, m_back + m_front, lat3, lon3);
    alertArea.append(Coordinate(lat3, lon3));
    GeographicUtil::getCoordinate(lat3, lon3, angle + 90, m_left + m_right, lat3, lon3);
    alertArea.append(Coordinate(lat3, lon3));
    GeographicUtil::getCoordinate(lat3, lon3, angle + 180, m_front + m_back, lat2, lon2);
    alertArea.append(Coordinate(lat2, lon2));
    alertArea.append(alertArea.first());
    m_alertAreas.append(alertArea);
#endif
}

void ShipManageB::onAis1Finished(AIS_1 *ais, bool vdo)
{
    if (!LonLatUtil::isValid(ais->Lat, ais->Lon))
    {
        delete ais;
        return;
    }

    if (!vdo && ais->Mmsi != m_ownShip->mmsi //
        && !m_shipList.contains(ais->Mmsi)   //
        && (qAbs(ais->Lat - m_ownShip->lat) > LONLATDISTANCE_THRESHOLD || qAbs(ais->Lon - m_ownShip->lon) > LONLATDISTANCE_THRESHOLD))
    {
        delete ais;
        return;
    }

    bool isNewShip;
    QSharedPointer<ModelShip> ship = getOrNewShip(ais->Mmsi, vdo, isNewShip);
    ship->lat = ais->Lat;
    ship->lon = ais->Lon;
    ship->rot = ais->Rot;
    ship->rotAis = ais->Rotais;
    ship->trueHeading = ais->Heading;
    ship->cog = ais->COG;
    ship->sog = ais->SOG;
    ship->trueHeading = ais->Heading;
    ship->time = GTime::getMsgTime(ais->UTCsecond);

#if 0
    // 更新方位距离
    if (vdo)
    { // 模拟数据
        static int cog = 0;
        static int ccount = 0;
        static double lat = 29.973;
        static double lon = 122.236;
        cog += 1;
        if (cog >= 360)
            cog = 0;
        ship->sog = 2;
        ship->cog = 190; // QRandomGenerator::system()->bounded(0, 359);
        ship->trueHeading = ship->cog;

        ccount++;
        // ship->lat -= 0.0003 * ccount;
        // ship->lon += 0.0003 * ccount;
        // qInfo() << "ownship coordinate:  " << ship->lat << ship->lon;
        double dis = ship->sog * 1852 / 2600 * ccount * 5;
        GeographicUtil::getCoordinate(lat, lon, ship->cog, dis, ship->lat, ship->lon);

        ship->to_bow = 100;
        ship->to_stern = 50;
        ship->to_port = 30;
        ship->to_starboard = 50;
    }
#endif

    delete ais;

    if (vdo)
    {
        onOwnShipChanged();
    }
}

void ShipManageB::onAis4Finished(AIS_4 *ais, bool vdo)
{
    if (ais->Year > 0 && ais->Month > 0 && ais->Day > 0 && ais->Hour < 24 && ais->Minute < 60)
    {

        QDateTime dt = GTime::getUtcTime();
        dt.setDate(QDate(ais->Year, ais->Month, ais->Day));
        dt.setTime(QTime(ais->Hour, ais->Minute, 0));
        GTime::setUtcTime(dt.toSecsSinceEpoch());
    }

    if (!LonLatUtil::isValid(ais->Lat, ais->Lon))
    {
        delete ais;
        return;
    }

    if (!vdo && ais->Mmsi != m_ownShip->mmsi //
        && !m_shipList.contains(ais->Mmsi)   //
        && (qAbs(ais->Lat - m_ownShip->lat) > LONLATDISTANCE_THRESHOLD || qAbs(ais->Lon - m_ownShip->lon) > LONLATDISTANCE_THRESHOLD))
    {
        delete ais;
        return;
    }

    bool isNewShip;
    auto ship = getOrNewShip(ais->Mmsi, vdo, isNewShip);

    ship->lat = ais->Lat;
    ship->lon = ais->Lon;

    delete ais;
}

void ShipManageB::onAis5Finished(AIS_5 *ais, bool vdo)
{
    // 对于黑匣子，船舶静态信息并不重要，只需要船舶类型
    //  bool isNewShip;
    //  auto ship = getOrNewShip(ais->Mmsi, vdo, isNewShip);

    if (!m_shipList.contains(ais->Mmsi))
    {
        delete ais;
        return;
    }
    auto ship = m_shipList[ais->Mmsi];
    ship->enname = ais->ShipName;
    ship->to_bow = ais->ToBow;
    ship->to_stern = ais->ToStern;
    ship->to_port = ais->ToPort;
    ship->to_starboard = ais->ToStarboard;
    ship->draught = ais->Draught;
    ship->setType(ais->ShipType);
    ship->destination = ais->DestinationName;
    if (ais->Month > 0 && ais->Day > 0 && ais->Hour < 24 && ais->Minute < 60)
    {
        QDateTime dt = GTime::getUtcTime();
        dt.setDate(QDate(dt.date().year(), ais->Month, ais->Day));
        dt.setTime(QTime(ais->Hour, ais->Minute, 0));
        ship->eta = dt.toSecsSinceEpoch();
    }
    delete ais;
}

void ShipManageB::onAis18Finished(AIS_18 *ais, bool vdo)
{
    if (!LonLatUtil::isValid(ais->lat, ais->lon))
    {
        delete ais;
        return;
    }

    if (!vdo && ais->Mmsi != m_ownShip->mmsi //
        && !m_shipList.contains(ais->Mmsi)   //
        && (qAbs(ais->lat - m_ownShip->lat) > LONLATDISTANCE_THRESHOLD || qAbs(ais->lon - m_ownShip->lon) > LONLATDISTANCE_THRESHOLD))
    {
        delete ais;
        return;
    }

    bool isNewShip;
    QSharedPointer<ModelShip> ship = getOrNewShip(ais->Mmsi, vdo, isNewShip);
    ship->sog = ais->speed;
    ship->lat = ais->lat;
    ship->lon = ais->lon;
    ship->cog = ais->course;
    ship->trueHeading = ais->heading;
    ship->time = GTime::getMsgTime(ais->second);
    delete ais;
    if (vdo)
    {
        onOwnShipChanged();
    }
}

void ShipManageB::onAis24Finished(AIS_24 *ais, bool vdo)
{
    if (!m_shipList.contains(ais->Mmsi))
    {
        delete ais;
        return;
    }
    // bool isNewShip;
    // QSharedPointer<ModelShip> ship = getOrNewShip(ais->Mmsi, vdo, isNewShip);
    auto ship = m_shipList[ais->Mmsi];
    ship->enname = ais->shipname;
    // ship->type = ais->model;
    // ship->type = ais->shiptype;
    ship->setType(ais->shiptype);
    ship->callsign = ais->callsign;
    ship->to_bow = ais->to_bow;
    ship->to_stern = ais->to_stern;
    ship->to_port = ais->to_port;
    ship->to_starboard = ais->to_starboard;
    delete ais;
}

void ShipManageB::onDPTFinished(DPT *dpt)
{
    m_depth = dpt->depth + dpt->offset;
    m_draught = dpt->offset;

    // emit waterDepthChanged(dpt->depth, dpt->offset);
    delete dpt;
}

void ShipManageB::onHDTFinished(double head)
{
    m_ownShip->trueHeading = head;
    if (ownValid())
    {
        updateAlertArea();
        if (GLOG)
            GLOG->debug("ownship trueHeading {}", m_ownShip->trueHeading);
        updateShips();
    }
}

void ShipManageB::onHDGFinished(HDG *hdg)
{
    m_ownShip->trueHeading = hdg->heading;
    delete hdg;
    if (ownValid())
    {
        updateAlertArea();
        updateShips();
    }
}

void ShipManageB::onGGAFinished(GGA *gga)
{
    if (gga->status == 0)
    {
        delete gga;
        return;
    }
    m_ownShip->time = GTime::getUtcTime_s();
    m_ownShip->lat = gga->lat;
    m_ownShip->lon = gga->lon;

    onOwnShipChanged();
    delete gga;
}

void ShipManageB::onGLLFinished(GLL *gll)
{
    if (gll->status == "A")
    {
        m_ownShip->time = GTime::getUtcTime_s();
        m_ownShip->lat = gll->lat;
        m_ownShip->lon = gll->lon;

        onOwnShipChanged();
    }
    delete gll;
}

void ShipManageB::onRMCFinished(RMC *rmc)
{
    if (rmc->status == "A")
    {
        GTime::setUtcTime(rmc->utc);
        m_ownShip->time = GTime::getUtcTime_s();
        m_ownShip->lat = rmc->lat;
        m_ownShip->lon = rmc->lon;
        m_ownShip->sog = rmc->speed;
        m_ownShip->cog = rmc->course;
        onOwnShipChanged();
    }
    delete rmc;
}

void ShipManageB::onVTGFinished(VTG *vtg)
{
    m_ownShip->sog = vtg->speed;
    m_ownShip->cog = vtg->course;
    updateAlertArea();
    updateShips();
    delete vtg;
}

void ShipManageB::onGNSFinished(GNS *gns)
{
    // m_ownShip->time = gns->utc;
    m_ownShip->time = GTime::getUtcTime_s();

    if (gns->latdirection == "S")
    {
        gns->lat = gns->lat * (-1);
    }
    m_ownShip->lat = gns->lat;

    if (gns->londirection == "W")
    {
        gns->lon = gns->lon * (-1);
    }
    m_ownShip->lon = gns->lon;
    onOwnShipChanged();
    delete gns;
}

/**
 * @brief 严格来说。这里处理过期船舶，如果过期的船舶原本在需要显示的半径范围内，就是在船舶数量统计内，
 *        需要调整m_arpaCount和m_aisCount。不过在正常工作中会不断接收到本船信息，会重新计算船舶数量，这里不做处理也是可以的。
 */
void ShipManageB::processExpiredShips()
{
    GLOG->debug("process expired ships......");
    m_isBusy = true;
    quint64 ctime = GTime::getUtcTime_s();
    int expiredCount = 0;
    foreach (auto ship, m_shipList)
    {
        if ((qAbs(m_ownShip->lat - ship->lat) > LONLATDISTANCE_THRESHOLD || qAbs(m_ownShip->lon - ship->lon) > LONLATDISTANCE_THRESHOLD) || qAbs(ctime - ship->time) > 7200)
        {
            // GLOG->debug("expired ship: {}", ship->mmsi);
            expiredCount++;
            cancelCollision(ship->mmsi);
            m_shipList.remove(ship->mmsi);
        }
    }
    GLOG->debug("expired ship count: {}", expiredCount);
    m_isBusy = false;
}

bool ShipManageB::isBusy() const
{
    return m_isBusy;
}

void ShipManageB::onRadiusChanged(double radius_nm)
{
    ShipManage::onRadiusChanged(radius_nm);
    updateShips();
}

void ShipManageB::onposStateChange(int state)
{
    m_posState = state;
    // emit posStateChange(state);
}

void ShipManageB::onOwnShipChanged()
{
    if (ownValid())
    {
        latlonAdjust(m_ownShip, 2);
        updateAlertArea();
        updateShips();
    }
}